package com.kk.tx.service.service;

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.interceptor.TransactionInterceptor;

import java.io.FileInputStream;
import java.io.FileNotFoundException;

@Service
@Slf4j
public class TransService {
    @Autowired
    private JdbcTemplate jdbcTemplate;


    /**
     * 检查异常
     *
     * @param from  转账者
     * @param to    收款者
     * @param amout 金额
     * @throws FileNotFoundException
     */
    @Transactional(rollbackFor = Exception.class)
    public void transfer(int from, int to, int amout) throws FileNotFoundException {

        // 查询原账户余额是否充足
        Integer fromBalance = jdbcTemplate.queryForObject ("select balance from account where accountNo = ? ", new Object[]{from}, Integer.class);
        if (fromBalance - amout >= 0) {
            jdbcTemplate.update (" update account set balance = balance + ?  where accountNo = ?", -amout, from);
            // 构建一个不存在文件，抛出异常
            new FileInputStream ("aaa");
            jdbcTemplate.update (" update account set balance = balance + ?  where accountNo = ?", amout, to);
        }

    }

    /**
     * 错误的 try-catch
     *
     * @param from  转账者
     * @param to    收款者
     * @param amout 金额
     * @throws FileNotFoundException
     */
    @Transactional(rollbackFor = Exception.class)
    public void transfer2(int from, int to, int amout) {

        // 查询原账户余额是否充足
        try {
            Integer fromBalance = jdbcTemplate.queryForObject ("select balance from account where accountNo = ? ", new Object[]{from}, Integer.class);
            if (fromBalance - amout >= 0) {
                jdbcTemplate.update (" update account set balance = balance + ?  where accountNo = ?", -amout, from);
                // 构建一个不存在文件，抛出异常
                new FileInputStream ("aaa");
                jdbcTemplate.update (" update account set balance = balance + ?  where accountNo = ?", amout, to);
            }
        } catch (Exception e) {
            e.printStackTrace ( );
//            throw new RuntimeException ();
            TransactionInterceptor.currentTransactionStatus ( ).setRollbackOnly ( );
        }
    }

/*    @Aspect
    @Component
    // 设置执行顺序的优先级(Ordered.LOWEST_PRECEDENCE 最低上面提高，数值越小越高，越大越低，所以是 -1
    @Order(Ordered.LOWEST_PRECEDENCE - 1)
    static class MyAspect {
        // 后置环绕:默认会在spring事务优先级后，所以跑出异常后，事务无感知
        // 解决方案：把优先级调至低于 springtx 优先级之前，既调高一些
        @Around("execution( * transfer*(..))")
        public Object around(ProceedingJoinPoint pjp) throws Throwable {
            try {
                log.info (">>>>>>>>>>>log:{}>>>>>>>>>>>>>", pjp.getTarget ( ));
                return pjp.proceed ( );// 调用下一个通知，或者目标方法（有通知调用通知，没有则调用目标方法）
            } catch (Exception e) {
                e.printStackTrace ( );
                return null;
            }
        }
    }*/

    /**
     * 切面顺序
     *
     * @param from  转账者
     * @param to    收款者
     * @param amout 金额
     * @throws FileNotFoundException
     */
    @Transactional(rollbackFor = Exception.class)
    public void transfer3(int from, int to, int amout) {

        // 查询原账户余额是否充足
        try {
            Integer fromBalance = jdbcTemplate.queryForObject ("select balance from account where accountNo = ? ", new Object[]{from}, Integer.class);
            if (fromBalance - amout >= 0) {
                jdbcTemplate.update (" update account set balance = balance + ?  where accountNo = ?", -amout, from);
                // 构建一个不存在文件，抛出异常
                new FileInputStream ("aaa");
                jdbcTemplate.update (" update account set balance = balance + ?  where accountNo = ?", amout, to);
            }
        } catch (Exception e) {
            e.printStackTrace ( );
            throw new RuntimeException ( );
        }
    }

    /**
     * 非 public
     *
     * @param from  转账者
     * @param to    收款者
     * @param amout 金额
     * @throws FileNotFoundException
     */
    @Transactional(rollbackFor = Exception.class)
    void transfer4(int from, int to, int amout) {

        // 查询原账户余额是否充足
        try {
            Integer fromBalance = jdbcTemplate.queryForObject ("select balance from account where accountNo = ? ", new Object[]{from}, Integer.class);
            if (fromBalance - amout >= 0) {
                jdbcTemplate.update (" update account set balance = balance + ?  where accountNo = ?", -amout, from);
                // 构建一个不存在文件，抛出异常
                new FileInputStream ("aaa");
                jdbcTemplate.update (" update account set balance = balance + ?  where accountNo = ?", amout, to);
            }
        } catch (Exception e) {
            e.printStackTrace ( );
            throw new RuntimeException ( );
        }
    }

    /**
     * 父子容器
     *
     * @param from  转账者
     * @param to    收款者
     * @param amout 金额
     * @throws FileNotFoundException
     */
    @Transactional(rollbackFor = Exception.class)
    public void transfer5(int from, int to, int amout) {

        // 查询原账户余额是否充足
        try {
            Integer fromBalance = jdbcTemplate.queryForObject ("select balance from account where accountNo = ? ", new Object[]{from}, Integer.class);
            if (fromBalance - amout >= 0) {
                jdbcTemplate.update (" update account set balance = balance + ?  where accountNo = ?", -amout, from);
                // 构建一个不存在文件，抛出异常
                new FileInputStream ("aaa");
                jdbcTemplate.update (" update account set balance = balance + ?  where accountNo = ?", amout, to);
            }
        } catch (Exception e) {
            e.printStackTrace ( );
            throw new RuntimeException ( );
        }
    }

    @Autowired
    public TransService transService;

    /**
     * 本类调用
     * 期望：有两个事务，分别处理自己的
     *
     * @param from  转账者
     * @param to    收款者
     * @param amout 金额
     * @throws FileNotFoundException
     */
    // 加入传播行为 REQUIRED（默认） 如果没有事务，就创建事务；如果已有事务，就用已经有的
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public void transfer61(int from, int to, int amout) {
        System.out.println ("111");
//         transfer62 (from,to,amout);
//         transService.transfer62 (from,to,amout);
        // 用 Aop的时候自己注入自己要注释掉
//        ((TransService) AopContext.currentProxy ( )).transfer62 (from, to, amout);
    }

    /**
     * 本类调用
     *
     * @param from  转账者
     * @param to    收款者
     * @param amout 金额
     * @throws FileNotFoundException
     */
    // 加入传播行为 REQUIRES_NEW   不管之前有没有事务，都会开启一个新的事务
    @Transactional(propagation = Propagation.REQUIRES_NEW, rollbackFor = Exception.class)
    public void transfer62(int from, int to, int amout) {
        System.out.println ("222");
        // 查询原账户余额是否充足
        try {
            Integer fromBalance = jdbcTemplate.queryForObject ("select balance from account where accountNo = ? ", new Object[]{from}, Integer.class);
            if (fromBalance - amout >= 0) {
                jdbcTemplate.update (" update account set balance = balance + ?  where accountNo = ?", -amout, from);
                // 构建一个不存在文件，抛出异常
                new FileInputStream ("aaa");
                jdbcTemplate.update (" update account set balance = balance + ?  where accountNo = ?", amout, to);
            }
        } catch (Exception e) {
            e.printStackTrace ( );
            throw new RuntimeException ( );
        }
    }


    /**
     * 测试原子性（多线程）
     *
     * @param from  转账者
     * @param to    收款者
     * @param amout 金额
     * @throws FileNotFoundException
     */
    @Transactional(rollbackFor = Exception.class)
    public  void transfer7(int from, int to, int amout) {

        // 查询原账户余额是否充足
        Integer fromBalance = jdbcTemplate.queryForObject ("select balance from account where accountNo = ? ", new Object[]{from}, Integer.class);
        log.info ("剩余：{}",fromBalance);
        if (fromBalance - amout >= 0) {
            jdbcTemplate.update (" update account set balance = balance + ?  where accountNo = ?", -amout, from);
            jdbcTemplate.update (" update account set balance = balance + ?  where accountNo = ?", amout, to);
        }
    }


}
